package com.mybpm.core.definition

import grails.core.GrailsApplication
import grails.util.Holders
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil
import java.lang.reflect.Field
import java.nio.file.Paths

/**
 * 流程加载服务
 */
@Service
public class ProcessLoadBpmnService {
    private static final Logger log = LoggerFactory.getLogger(ProcessLoadBpmnService.class)

    @Autowired
    ProcessParseBpmnService processParseBpmnService
    @Autowired
    GrailsApplication grailsApplication = Holders.grailsApplication

    private String processesPath = "/bpmn/**/*.bpmn"

    public void bpmn2MyBpm(String bpmPath) {
        log.debug("----------loadXml")
        def resources = grailsApplication.mainContext.getResources("file:" + bpmPath + processesPath)
        resources.each { resource ->
            Map proc = loadXml(resource.file)
            String xml = toMybpmXml(proc)
            String newFilePath = resource.file.path.substring(bpmPath.length())
            newFilePath = newFilePath.replace(File.separator + "bpmn" + File.separator, File.separator + "process" + File.separator).replace(".bpmn", ".xml")
            new File(bpmPath + newFilePath).withWriter('UTF-8') { writer ->
                writer.write(xml)
            }
        }
    }

    /**
     * 加载流程
     */
    public Map<String, Map> loadXml(File file) {
        log.debug("----------xmlFile={}", file.path)
        String xml = file.getText('UTF-8')
        log.debug("----------loadXml{}", xml)
        Map proc = processParseBpmnService.parse(xml.replaceAll(">\\s+<", "><").replaceAll("[\\r\\n]", ""))
        return proc
    }

    /**
     * 转换为MyBPM的流程xml
     */
    public String toMybpmXml(Map proc) {
        def nodes = proc.nodes*.value
        def xml2 = new StreamingMarkupBuilder().bind {
            mkp.xmlDeclaration() // 添加 XML 声明
            process(getAttributes(proc.process, ProcessParseService.processProperties)) {
                start(getAttributes(proc.start, ProcessParseService.startProperties)) {
                    proc.start.transitions.each { XmlTransition tr ->
                        transition(getAttributes(tr, ProcessParseService.transitionProperties))
                    }
                }
                nodes.each { XmlNode xn ->
                    node(getAttributes(xn, ProcessParseService.nodeProperties)) {
                        xn.transitions.each { XmlTransition tr ->
                            transition(getAttributes(tr, ProcessParseService.transitionProperties))
                        }
                    }
                }
                end(getAttributes(proc.end, ProcessParseService.endProperties)) {}
            }
        }
        XmlUtil.serialize(xml2)
    }

    private Map getAttributes(Object bean, List<String> names) {
        def attributes = [:]
        bean.class.declaredFields.each { Field field ->
            if (field.modifiers == java.lang.reflect.Modifier.PUBLIC) {
                field.setAccessible(true)
                def value = field.get(bean)
                if (value != null && field.name in names) {
                    attributes[field.name] = value.toString()
                }
            }
        }
        return attributes
    }
}